#pragma once
#include <iostream>
#include <memory>
#include "socket.hpp"
#include "buffer.hpp"
#include "channel.hpp"
#include "eventloop.hpp"
#include "types.h"

typedef enum {
    DISCONNECTED, 
    CONNECTING, 
    CONNECTED, 
    DISCONNECTING
}State;

class Connection: public std::enable_shared_from_this<Connection> {
    private:
        uint64_t _id; 
        EventLoop *_loop;
        std::unique_ptr<Socket> _sock;
        std::unique_ptr<Channel> _channel;
        State _state;
        Buffer _in_buffer;
        Buffer _out_buffer;
        Any _context;
    private:
        /*由外界设置的回调函数，对外的接口都用的是shared_ptr，防止Connection被释放后操作出错*/
        ConnectionComplateCallback _connected_callback; //连接建立完毕后的回调函数，主要用于不同协议设置context上下文信息
        ConnectionMsgCallback _message_callback; // 有消息到来后的回调函数，不同的协议对in_buffer数据的不同处理
        ConnectionCloseCallback _close_callback; //关闭时最后的回调
    private:
        void Connection::establisehd_in_loop() {
            assert(this->_state == CONNECTING);
            this->_state = CONNECTED;
            /*将当前channel添加到_loop的事件监控中，并启动可读事件监控*/
            _channel->enable_read();
            /*调用外界设置的连接成功回调函数--这个函数后边主要是设置context上下文操作*/
            if (_connected_callback) _connected_callback(shared_from_this());
            /*给当前的connction添加一个超时任务，超时后销毁资源*/
            _loop->timer_task_enqueue(std::bind(&Connection::on_time_destroyed, this), _id);
        } 
        void Connection::enable_read_in_loop() {
            if (_state == DISCONNECTED) return;
            return _channel->enable_read();
        }
        void Connection::disable_read_in_loop() {
            if (_state == DISCONNECTED) return;
            return _channel->disable_read();
        }
        void Connection::shutdown_in_loop() {
            /*如果已经是待关闭状态就什么都不用做了*/
            if (_state == DISCONNECTED) return;
            _state = DISCONNECTING;
            /*如果要关闭，又没有待发送的数据，则直接关闭套接字，内存资源等定时器时间到了进行释放*/
            if (_out_buffer.writeable_size() == 0) {
                return close_in_loop();
            }
            /*如果有数据待发送，又要关闭连接，则启动可写事件，写完数据后再关闭*/
            if (_channel->writeable() == false) {
                _channel->enable_write();
            }
        }
        void Connection::send_in_loop(const void *msg, size_t len) {
            /*连接处于实际要释放关闭的状态，则什么都不需要做了*/
            if (_state == DISCONNECTED)  return; 
            /*如果当前发送缓冲区中没有数据，就直接开始写， 如果有数据就把数据加入缓冲区*/
            int ret = 0, remain = len;
            if (_out_buffer.readable_size() == 0) {
                assert(_sock->fd() == _channel->fd());
                ret = _sock->nonblock_send(msg, len);
                if (ret < 0) {
                    /*其实这里直接调用handle_close也行，因为send_in_loop本身就是在eventloop线程中被执行调用的*/
                    close_in_loop();
                }
                remain -= ret;
            }
            /*将剩余没有发送完的数据添加到发送缓冲区中*/
            _out_buffer.append((char*)msg + ret, remain);
            /*如果没有启动可写监控，则启动可写事件监控*/
            if (_channel->writeable() == false) {
                _channel->enable_write();
            }
            return ;
        }
        /*读取所有数据到接收缓冲区中*/
        void Connection::handle_read(){
            char buf[65536];
            int ret;
            assert(_sock->fd() == _channel->fd());
            _loop->timer_refresh(_id);
            while((ret = _sock->nonblock_recv(buf, 65535)) > 0) {
                _in_buffer.append(buf, ret);
            }
            /*如果读取出错了，或者连接断开了，则直接关闭*/
            if (ret < 0) {
                close_in_loop();
                return;
            }
            /*拿到数据后调用外界传入的消息处理函数*/
            if (_message_callback) _message_callback(shared_from_this(), &_in_buffer);
        }
        void Connection::handle_write() {
            assert(_sock->fd() == _channel->fd());
            /*有事件则刷新定时任务*/
            _loop->timer_refresh(_id);
            /*写入缓冲区有数据可读，表示的是有数据可写，则发送数据*/
            if (_out_buffer.readable_size() != 0){
                /*对发送缓冲区中的数据进行全部发送*/
                ssize_t ret = _sock->nonblock_send(_out_buffer.peek(), _out_buffer.readable_size());
                if (ret < 0) {
                    close_in_loop();
                }
                /*发送缓冲区读位置向后偏移ret长度*/
                _out_buffer.retrieve(ret);
            }
            if (_out_buffer.readable_size() == 0) {
                /*若发送缓冲区中没有数据待发送，则解除写事件监控*/
                _channel->disable_write();
                /*若处于待关闭状态，则关闭释放资源*/
                if (_state == DISCONNECTING) {
                    close_in_loop();
                }
            }
        }
        void Connection::handle_error() {
            /*目前并未对错误事件进行特殊操作，所以暂时可以不管，统一按照关闭处理*/
            handle_close();
        }
        void Connection::handle_close() {
            /*解除所有的事件监控*/
            if (this->_state != DISCONNECTED) {
                this->_state = DISCONNECTED;
                _channel->disable_all();
            }
            /*这个主要是移除poller中保存的channel信息以及epoll中的事件监控*/
            _channel->remove();
            /*关闭描述符*/
            _sock->close();
        }
    public:
        Connection::Connection(EventLoop *loop, int fd, uint64_t id):
            _id(id), 
            _sock(new Socket(fd)), 
            _loop(loop), 
            _channel(new Channel(loop, fd)), 
            _state(CONNECTING) {
            _sock->set_nonblock();
            _channel->set_read_callback(std::bind(&Connection::handle_read, this));
            _channel->set_write_callback(std::bind(&Connection::handle_write, this));
            _channel->set_error_callback(std::bind(&Connection::handle_error, this));
            _channel->set_close_callback(std::bind(&Connection::handle_close, this));
        }
        Connection::~Connection() { LOG("release conn source:%p", this);  }
        EventLoop *Connection::get_loop() { return _loop; }
        int Connection::id() { return _id; } 
        int Connection::fd() { assert(_sock->fd() == _channel->fd());  return _sock->fd(); }
        Buffer *Connection::input_buffer() { return &_in_buffer; }
        Buffer *Connection::output_buffer() { return &_out_buffer; }
        void Connection::set_context(const Any &context) { _context = context; }
        Any *Connection::get_context() { return &_context; }
        void Connection::set_connected_callback(const ConnectionComplateCallback &cb) { _connected_callback = cb; }
        void Connection::set_on_message_callback(const ConnectionMsgCallback &cb) { _message_callback = cb; }
        void Connection::set_close_callback(const ConnectionCloseCallback &cb) { _close_callback = cb; }
        void Connection::send(const void *msg, size_t len) {
            if (_loop->is_in_loop_thread()) {
                send_in_loop(msg, len);
            }else {
                _loop->run_in_loop(std::bind(&Connection::send_in_loop, this, msg, len));
            }
        }
        void Connection::shutdown() {
            if (_loop->is_in_loop_thread()) {
                shutdown_in_loop();
            }else {
                _loop->run_in_loop(std::bind(&Connection::shutdown_in_loop, this));
            }
        }
        void Connection::enable_read() {
            if (_loop->is_in_loop_thread()) {
                enable_read_in_loop();
            }else {
                _loop->run_in_loop(std::bind(&Connection::enable_read_in_loop, this));
            }
        }
        void Connection::disable_read() {
            if (_loop->is_in_loop_thread()) {
                disable_read_in_loop();
            }else {
                _loop->run_in_loop(std::bind(&Connection::disable_read_in_loop, this));
            }
        }
        /*这个函数是提供给TcpServer中使用，新连接创建成功后压入eventloop的连接完成后的处理函数，主要功能是设置Connection状态，以及添加可读事件监控，然后调用外部设置的连接完成回调*/
        void Connection::conn_established() {
            if (_loop->is_in_loop_thread()) {
                establisehd_in_loop();
            }else {
                _loop->run_in_loop(std::bind(&Connection::establisehd_in_loop, this));
            }
            return ;
        }
};
